#ifndef __EVENTLOOP_HPP__
#define __EVENTLOOP_HPP__

#include <mutex>
#include <thread>
#include <memory>
#include <sys/eventfd.h>
#include "timerwheel.hpp"

using Functor = std::function<void()>; // 任务类型

class EventLoop
{
public:
    EventLoop() : _thread_id(std::this_thread::get_id()), _event_fd(CreateEventFd()),
                  _event_channel(new Channel(_event_fd, this)), _timerwheel(this)
    {
        _event_channel->SetReadCallback(std::bind(&EventLoop::ReadEventFd, this)); // 为EventFd设置可读事件回调，读取EventFd中的数据
        _event_channel->EnableRead();                                              // 打开对EventFd的读事件监控
    }

    /* 某个任务必须在线程中执行 */
    void AssertInLoop()
    {
        assert(_thread_id == std::this_thread::get_id());
    }

    /* 判断当前要执行的任务是否在当前线程内，是就执行，不是就压入到队列 */
    void RunInLoop(const Functor &cb)
    {
        if (IsInLoop())
            cb();
        else
            QueueInLoop(cb);
    }
    /* 将操作压入到任务池 */
    void QueueInLoop(const Functor &cb)
    {
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _tasks.push_back(cb);
        }
        // 唤醒可能因为没有事件就绪而导致的epoll阻塞
        WeakUpEventFd();
    }
    /* 判断当前线程是否是当前EventLoop对应的线程 */
    bool IsInLoop() const
    {
        return _thread_id == std::this_thread::get_id();
    }
    /* 更新事件监控 没有就添加，有就修改 */
    void UpdateEvent(Channel *channel)
    {
        _poller.UpdateEvent(channel);
    }
    /* 移除事件监控 */
    void RemoveEvent(Channel *channel)
    {
        _poller.RemoveEvent(channel);
    }

    /* 添加定时任务 */
    void TimerAdd(uint64_t id, uint32_t timeout, const TaskFunc &task_cb)
    {
        _timerwheel.TimerAdd(id, timeout, task_cb);
    }
    /* 刷新定时任务 */
    void TimerRefresh(uint64_t id)
    {
        _timerwheel.TimerRefresh(id);
    }
    /* 取消定时任务 */
    void TimerCancel(uint64_t id)
    {
        _timerwheel.TimerCancel(id);
    }
    /* 是否存在某个定时任务（此接口只能在该线程中被使用） */
    bool HasTimer(uint64_t id)
    {
        return _timerwheel.HasTimer(id);
    }

    /* 创建EventFd */
    static int CreateEventFd()
    {
        int evfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
        if (evfd < 0)
        {
            ERR_LOG("eventfd create failed");
            exit(ERROR_EVENTFD);
        }
        return evfd;
    }
    /* 读取EventFd中的数据，将eventfd中的计数器的数据重置为0 */
    void ReadEventFd()
    {
        uint64_t res = 0;
        ssize_t n = read(_event_fd, &res, sizeof(res));
        if (n < 0)
        {
            if (errno == EINTR || errno == EAGAIN)
                return;
            ERR_LOG("eventfd read failed");
            exit(ERROR_EVENTFD);
        }
        return;
    }
    /* 唤醒可能因为没有事件就绪而导致的epoll阻塞——其实就是向eventfd中写入一个数据，触发eventfd的可读事件 */
    void WeakUpEventFd()
    {
        uint64_t val = 1;
        ssize_t n = write(_event_fd, &val, sizeof(val));
        if (n < 0)
        {
            if (errno == EINTR)
                return;
            ERR_LOG("eventfd read failed");
            exit(ERROR_EVENTFD);
        }
        return;
    }

    /* 执行任务池中的所有任务 */
    void RunAllTask()
    {
        std::vector<Functor> functors;
        {
            std::unique_lock<std::mutex> lock(_mutex); // 用于将任务池中的任务全部取出
            _tasks.swap(functors);                     // 取出所有任务，准备执行
        }
        for (auto &f : functors)
        {
            f(); // 执行任务
        }
    }
    /* 三步——事件监控->就绪事件处理->执行任务 */
    void Start()
    {
        while (true)
        {
            // 1. 事件监控
            std::vector<Channel *> actives;
            _poller.Poll(actives);
            // 2. 事件处理
            for (auto &channel : actives)
            {
                channel->HandleEvent();
            }
            // 3. 执行任务
            RunAllTask();
        }
    }

private:
    std::thread::id _thread_id;              // 对应线程的线程id
    int _event_fd;                           // 用于通知事件，是一种通知机制或者通知模型
    std::unique_ptr<Channel> _event_channel; //
    Poller _poller;                          // 用来监控事件
    std::vector<Functor> _tasks;             // 任务队列/任务池
    std::mutex _mutex;                       // 互斥锁，保证任务池操作是线程安全的
    TimerWheel _timerwheel;                  // 定时轮
};

/* 移除监控——从EventLoop中移除需要监控的事件 */
void Channel::Remove()
{
    _loop->RemoveEvent(this);
}
/* 添加监控——存在则修改，不存在则添加 */
void Channel::Update()
{
    _loop->UpdateEvent(this);
}

/* 添加定时任务（EventLoop线程中进行） */
void TimerWheel::TimerAdd(uint64_t id, uint32_t timeout, const TaskFunc &task_cb)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerAddInLoop, this, id, timeout, task_cb));
}
/* 刷新定时任务（EventLoop线程中进行） */
void TimerWheel::TimerRefresh(uint64_t id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerRefreshInLoop, this, id));
}
/* 取消定时任务（EventLoop线程中进行） */
void TimerWheel::TimerCancel(uint64_t id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerCancelInLoop, this, id));
}

#endif